package net.jcip.chapter4;

import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import net.jcip.annotations.*;


/**
 * MonitorVehicleTracker
 * <p/>
 * Monitor-based vehicle tracker implementation
 * <p>
 * map中的值 MutablePoint并非线程安全，但是MonitorVehicleTracker 类时线程安全的。
 * 它所包含的 Map对象和可变的 Point对象都未曾发布，当需要返回车辆的位置时，
 * 通过 MutablePoint 拷贝构造函数或者 deepCopy 方法来复制正确的值，从而生成一个新的Map对象，
 * 并且该对象中的值与原有 Map 对象的 Key值和 value 值都相同。
 * 但在车辆容器非常大的情况下将极大地降低性能，如果调用者需要每辆车的最新信息，那么这就是缺点，因为这需要非常频繁地刷新快照。
 *
 * @author Brian Goetz and Tim Peierls
 */
@ThreadSafe
public class MonitorVehicleTracker {


    @GuardedBy("this")
    private final Map<String, MutablePoint> locations;  // 这个 被 设置 为 final ;



    MonitorVehicleTracker(Map<String, MutablePoint> locations) {
        this.locations = deepCopy(locations);
    }

    synchronized Map<String, MutablePoint> getLocations() {
        return deepCopy(locations);
    }

    synchronized MutablePoint getLocation(String id) {
        MutablePoint loc = locations.get(id);
        return loc == null ? null : new MutablePoint(loc);
    }

    synchronized void setLocation(String id, int x, int y) {
        MutablePoint loc = locations.get(id);
        if (loc == null) {
            throw new IllegalArgumentException("No such ID: " + id);
        }
        loc.x = x;
        loc.y = y;
    }

    private static Map<String, MutablePoint> deepCopy(Map<String, MutablePoint> m) {

        Map<String, MutablePoint> result = new HashMap<>();

        for (String id : m.keySet()) {

            result.put(id, new MutablePoint(m.get(id)));
        }

        return Collections.unmodifiableMap(result);
    }


    public static void main(String[] args) throws InterruptedException {


        HashMap<String, MutablePoint> map = new HashMap<>();

        map.put("大众", new MutablePoint(1, 2));

        MonitorVehicleTracker monitorVehicleTracker = new MonitorVehicleTracker(map);


        for (int i = 0; i < 100; i++) {
            final int j = i;
            Constant4.executorService.execute(() -> {
                monitorVehicleTracker.setLocation("大众", j * 10, j * 10);
                Constant4.countDownLatch.countDown();

            });
        }

        Constant4.countDownLatch.await(10, TimeUnit.SECONDS);

        System.out.println(monitorVehicleTracker.getLocation("大众"));


    }

}

